package com.irisking.ikaisdk;

import com.irisking.ikaisdk.common.JacksonUtil;
import com.irisking.ikaisdk.dataStruct.BasicJsonRec;
import com.irisking.ikaisdk.dataStruct.BasicJsonResp;
import com.irisking.ikaisdk.dataStruct.DeviceConnInfo;
import com.irisking.ikaisdk.eventListener.EventManager;
import com.irisking.ikaisdk.netCommond.NetCommand;
import com.irisking.server.NettyServer;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;


public abstract class AbstractServerSDK {
    /**
     * 服务端下发请求
     */
    public NetCommand netCommand = null;

    /**
     * 注册事件
     */
    public EventManager eventManager = null;

    /**
     * 在线设备列表
     */
    private ConcurrentHashMap<String, DeviceConnInfo> onlineClients = new ConcurrentHashMap<>();

    /**
     * 设备端回应数据集合
     */
    private List<BasicJsonResp> AckRespList = new ArrayList<BasicJsonResp>();

    /**
     * 锁
     */
    private Object respListLock = new Object();

    /**
     *
     */
    private NettyServer netNettyServer=null;

    /**
     * 启动Socket服务
     * @param port
     */
    public void initServer(int port) {
        DispatchHandler dispatchHandler = new DispatchHandler(this);
        netNettyServer = new NettyServer(port,dispatchHandler);
        //启动网络服务
        netNettyServer.startServer();
    }

    /**
     * 添加Ack Resp消息到队列
     * @param data
     */
    public void addAckResp(BasicJsonResp data) {
        synchronized (respListLock){
            AckRespList.add(data);
        }
    }

    /**
     * 获取全部Ack Resp消息
     * @return
     */
    public List<BasicJsonResp> getAckResplist() {
        return AckRespList;
    }

    /**
     * 从队列中移除Ack Resp消息
     * @param resp
     */
    public void removeAckResp(BasicJsonResp resp) {
        synchronized (respListLock){
            AckRespList.add(resp);
        }
    }

    /**
     * 通过设备序列号，获取客户端连接唯一key
     * @param sn
     * @return
     */
    public String getClientKey(String sn)
    {
        String key="" ;

        System.out.println("getDicKey:" + sn);
        List<DeviceConnInfo> connInfoList = Collections.list(onlineClients.elements());
        DeviceConnInfo deviceConnInfo = connInfoList.stream()
                .distinct()
                .filter(d->sn.equals(d.getSn()))
                .findFirst().orElse(null);

        if (deviceConnInfo!=null)
            return deviceConnInfo.getDevicekey();
        System.out.println("key:" + key );
        return key;
    }

    /**
     * 获取设备连接
     * @param key
     * @return
     */
    public DeviceConnInfo getClientByKey(String key) {
        return onlineClients.get(key);
    }

    /**
     * 移除设备连接
     * @param key
     */
    public void removeClientByKey(String key) {
        onlineClients.remove(key);
    }

    /**
     * 添加设备
     * @param key
     * @param devInfo
     */
    public void putClient(String key, DeviceConnInfo devInfo) {
        onlineClients.put(key,devInfo);
    }

    /**
     * 发送Ack 确认消息
     * @param resp
     * @param sn
     */
    public void SendAckDataToDevSn(BasicJsonResp resp, String sn) {
        String key = getClientKey(sn);
        String json  =  JacksonUtil.getInstance().toJson (resp);
        // System.out.println("key:"+key+",json:" + json);
        netNettyServer.sendAckData(key,json);
    }

    /**
     * 发送数据并读取设备回应
     * @param sn
     * @param rec
     * @return
     */
    public BasicJsonResp SendCommandAndReadAck(String sn, BasicJsonRec rec)
    {
        if (sn==null) {
            return new BasicJsonResp(-1, "设备sn不能为空！");
        }

        String key = getClientKey(sn);
        if (key==null) {
            return new BasicJsonResp(-2, "已连接设备中不包含此设备");
        }

        rec.setTimestamp(getTimeStamp());
        rec.setSn(sn);

        String json  =  JacksonUtil.getInstance().toJson (rec);
        netNettyServer.sendCommandData(key,json);

        //记住处理时间，超时后未取得正确的信息则返回
        long tickCount = System.currentTimeMillis();
        while ((System.currentTimeMillis() - tickCount) <= 20000)
        {
            try {

                BasicJsonResp resp = getAckResplist().stream()
                        .distinct()
                        .filter(d -> d.getSn() == sn && d.getOperation() == rec.getOperation() && d.getTimestamp() == rec.getTimestamp())
                        .findAny().orElse(null);

                if (resp != null) {
                    removeAckResp(resp);
                    return resp;
                }
            }
            catch (Exception ex) {
                return null;
            }
        }
        return null;
    }

    /**
     *
     */
    private Object _timeStampLock = new Object();

    /**
     *
     */
    private int _timeStamp;
    /**
     * 生成返回的时间戳
     * @return
     */
    private long getTimeStamp()
    {
        long timestamp;
        synchronized (_timeStampLock) {
            _timeStamp ++;
            timestamp = System.currentTimeMillis() + _timeStamp;
        }
        return timestamp;
    }
}
